package example.simple_mindmap.common.designs.theadPool;



import example.simple_mindmap.common.designs.theadPool.strategy.error.CollectError;
import example.simple_mindmap.common.designs.theadPool.strategy.error.IErrorStrategy;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Program: 8.mindmap
 * @Author: 海里的鱼
 * @Create: 2024-08-26 10:26
 * @Name: TODO
 * @Desc: TODO
 */
public class BulkExecuteHandler<T extends BulkTask> {
    //成功列表
    private Long numOfSuccess = 0L;
    //失败列表
    private Long numOfError = 0L;
    //开始时间
    protected LocalDateTime startTime;
    //结束时间
    protected LocalDateTime endTime;
    //线程池
    private static volatile ExecutorService threadPool;
    //任务集合
    private BulkTaskCollection<T> taskCollection;
    //失败任务集合
    private List<String> errorTasks = new ArrayList<String>();
    //任务执行失败后的策略
    private IErrorStrategy errorStrategy = new CollectError();
    //重试次数
    private AtomicInteger retryCount = new AtomicInteger(0);



    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 构造方法
     * @Describe: TODO
     **/
     public BulkExecuteHandler(BulkTaskCollection<T> taskCollection) {
        this.taskCollection = taskCollection;
        //单例的懒汉模式
         if (threadPool == null) {
             synchronized (BulkExecuteHandler.class) {
                 if (threadPool == null) {
                     threadPool = BulkThreadPool.executorService();
                 }
             }
         }
    }

    public BulkExecuteHandler() {
        //单例的懒汉模式
        if (threadPool == null) {
            synchronized (BulkExecuteHandler.class) {
                if (threadPool == null) {
                    threadPool = BulkThreadPool.executorService();
                }
            }
        }
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 添加任务
     * @Describe: TODO
     **/
    public String add(T task) {
        //执行任务重命名策略
        return taskCollection.add(task);

    }

    public int add(Collection<T> tasks) {
        return taskCollection.add(tasks);
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 执行任务集合
     * @Describe: TODO
     **/
     public boolean executeTasks(){
         //判断任务集是否为空
         if(null == taskCollection  || taskCollection.size() == 0){
             new BulkExecuteException("任务为空").printStackTrace();
             return false;
         }

         //执行前清空信息
         cleanInfo();

         boolean isSuccess = true;
         CountDownLatch cdl = new CountDownLatch(taskCollection.size());
         this.startTime = LocalDateTime.now();


         for(BulkTask task : taskCollection.getTasks()){
             threadPool.execute(()->{
                 //执行任务
                 if(!execute(task)){
                    errorStrategy.processError(this,task);
                 }

                 if(task.getState() == TaskEnum.FAILED) this.numOfError++;
                 if(task.getState() == TaskEnum.SUCCESS) this.numOfSuccess++;
                 cdl.countDown();
             });
             isSuccess = isSuccess && task.getState() == TaskEnum.SUCCESS;
         }

         try {
             cdl.await();
         } catch (InterruptedException e) {
             new RuntimeException(e).printStackTrace();
             return false;
         }

         this.endTime = LocalDateTime.now();
         return isSuccess;
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 执行单个任务
     * @Describe: TODO
     **/
     public boolean executeTask(BulkTask task) {

         //执行前清空信息
         cleanInfo();

        this.startTime = LocalDateTime.now();
        //执行任务
        if(!execute(task)){
            errorStrategy.processError(this,task);
        }
        if(task.getState() == TaskEnum.FAILED) this.numOfError++;
        if(task.getState() == TaskEnum.SUCCESS) this.numOfSuccess++;
        //任务结束
        this.endTime = LocalDateTime.now();
        return task.getState() == TaskEnum.SUCCESS;
    }

    /* ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 清空信息
     * @Describe: TODO
     **/
     private void cleanInfo(){
         this.numOfSuccess = 0L;
         this.numOfError = 0L;
         this.startTime = null;
         this.endTime = null;
         this.retryCount = new AtomicInteger(0);
         this.errorTasks = new ArrayList<String>();
    }

    /* ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 执行一次任务
     * @Describe: TODO
     **/
     private boolean execute(BulkTask task){
         //判断任务是否为空
         if(null == task){
             new BulkExecuteException("任务为空").printStackTrace();
             return false;
         }
        //执行的初始时间
        task.setStartTime(LocalDateTime.now());
        //修改状态为"任务开始"
        task.setState(TaskEnum.EXECUTING);
        //执行任务
         try {
             if(!task.executeFunction()){
                 //执行的结束时间
                 task.setEndTime(LocalDateTime.now());
                 //修改状态为"执行失败"
                 task.setState(TaskEnum.FAILED);
                 return false;
             }
         } catch (Exception e) {
             e.printStackTrace();
             //执行的结束时间
             task.setEndTime(LocalDateTime.now());
             //修改状态为"执行失败"
             task.setState(TaskEnum.FAILED);
             return false;
         }
         //执行的结束时间
        task.setEndTime(LocalDateTime.now());
        //修改状态为"执行成功"
        task.setState(TaskEnum.SUCCESS);
        return true;
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 错误重试
     * @Describe: TODO
     **/
     public boolean errorRetry(BulkTask task){
         return execute(task);
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取所有执行结果
     * @Describe: TODO
     **/
     public Map<String, Object> getExecuteInfo(){
         Map<String,Object> info = null;
         try {
             info = new HashMap<>();
             info.put("success", this.numOfSuccess);
             info.put("error", this.numOfError);
             info.put("count", (numOfSuccess+numOfError));
             info.put("startTime", this.startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
             info.put("endTime", this.endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
             info.put("runningTime", ChronoUnit.MILLIS.between(startTime, endTime));
             info.put("retryCount", this.retryCount);
         } catch (Exception e) {
             new BulkExecuteException("获取任务执行信息失败，可能是因为任务集没有开始执行").printStackTrace();
             return new HashMap<>();
         }
         return info;
    }

    public int getRetryCount() {
        return retryCount.get();
    }

    public void addRetryCount() {
        this.retryCount.incrementAndGet();
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取任务总数
     * @Describe: TODO
     **/
     public Long NumCount() {
        return numOfSuccess+numOfError;
    }

    /** ---------------------------------------------------------------------------------------------------------------------
     * @Method  : 获取所有任务的执行时间
     * @Describe: TODO
     **/
     public Long getRunningTime(){
        return ChronoUnit.MILLIS.between(startTime, endTime);
    }

    public Long getNumOfSuccess() {
        return numOfSuccess;
    }

    public void setNumOfSuccess(Long numOfSuccess) {
        this.numOfSuccess = numOfSuccess;
    }

    public Long getNumOfError() {
        return numOfError;
    }

    public void setNumOfError(Long numOfError) {
        this.numOfError = numOfError;
    }


    public LocalDateTime getStartTime() {
        return startTime;
    }

    public void setStartTime(LocalDateTime startTime) {
        this.startTime = startTime;
    }

    public LocalDateTime getEndTime() {
        return endTime;
    }

    public void setEndTime(LocalDateTime endTime) {
        this.endTime = endTime;
    }
    public IErrorStrategy getErrorStrategy() {
        return errorStrategy;
    }

    public void setErrorStrategy(IErrorStrategy errorStrategy) {
        this.errorStrategy = errorStrategy;
    }

    public List<String> getErrorTasks() {
        return errorTasks;
    }

    public void addErrorTask(String name) {
         this.errorTasks.add(name);
    }
    public BulkTaskCollection getTaskCollection() {
        return taskCollection;
    }

    public void setTaskCollection(BulkTaskCollection taskCollection) {
        this.taskCollection = taskCollection;
    }

    public static ExecutorService getThreadPool() {
        return threadPool;
    }

    public static void setThreadPool(ExecutorService threadPool) {
        BulkExecuteHandler.threadPool = threadPool;
    }


}
